/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ASAInst;

import ASAExpr.ASAExpr;
import exception.DivisionByZeroException;
import exception.FonctionNonDefinieException;
import exception.NbParametresIncorrectException;
import exception.VariableNonDeclareeException;
import generation.GestionFonctions;
import generation.GestionVariables;
import java.util.List;
import java.util.Map;

/**
 *
 * @author FM & KB
 */
public class ASAInstAppelFonction extends ASAInst {

    private String nomFonction;
    //String = Nom de la future variable
    //ASAExpr = Valeur de la variable de le niveau actuel
    private Map<String, ASAExpr> mapParametres;

    //Declaration
    public ASAInstAppelFonction(String nomFonction, Map<String, ASAExpr> mapParametres) {
        this.nomFonction = nomFonction;
        this.mapParametres = mapParametres;
    }

    @Override
    public void executer() throws VariableNonDeclareeException, DivisionByZeroException{
        try {
            //On récupère la fonction déclarée dans la classe de gestion des fonctions
            ASAInstFonction fonction = GestionFonctions.getFonction(this.nomFonction);
            int nbParamEnvoyes = mapParametres.size();
            List<String> nomsParametres = fonction.getNomsParametres();
            int nbParamAttendus = nomsParametres.size();
            if (nbParamEnvoyes != nbParamAttendus) {
                throw new NbParametresIncorrectException(nbParamEnvoyes, nbParamAttendus);
            }

            int numParam = 0;
            String nomParamDefinitif;
            //On passe la valeur des paramètres a la fonction
            GestionVariables.ajouterFonction(nomFonction);
            for (String nomParam : this.mapParametres.keySet()) {
                nomParamDefinitif = nomsParametres.get(numParam);
                GestionVariables.declarerVariable(nomFonction, nomParamDefinitif);
                GestionVariables.getVariable(nomFonction, nomParamDefinitif).setValeur(mapParametres.get(nomParam).evalue());
                numParam++;
            }
            //On execute la fonction récupérée
            fonction.executer();
        } catch (FonctionNonDefinieException fnde) {
            System.out.print(fnde.getMessage());
        } catch (NbParametresIncorrectException npi) {
            System.out.print(npi.getMessage());
        }
    }

    public ASAInstFonction initialiseMain()
            throws FonctionNonDefinieException, NbParametresIncorrectException, VariableNonDeclareeException, DivisionByZeroException {
        //On récupère la fonction déclarée dans la classe de gestion des fonctions
        ASAInstFonction fonction = GestionFonctions.getFonction(this.nomFonction);
        int nbParamEnvoyes = mapParametres.size();
        List<String> nomsParametres = fonction.getNomsParametres();
        int nbParamAttendus = nomsParametres.size();
        if (nbParamEnvoyes != nbParamAttendus) {
            throw new NbParametresIncorrectException(nbParamEnvoyes, nbParamAttendus);
        }

        int numParam = 0;
        String nomParamDefinitif;
        //On passe la valeur des paramètres a la fonction
        GestionVariables.ajouterFonction(nomFonction);
        for (String nomParam : this.mapParametres.keySet()) {
            nomParamDefinitif = nomsParametres.get(numParam);
            GestionVariables.declarerVariable(nomFonction, nomParamDefinitif);
            GestionVariables.getVariable(nomFonction, nomParamDefinitif).setValeur(mapParametres.get(nomParam).evalue());
            numParam++;
        }

        //On retourne la fonction récupérée
        return fonction;
    }

    @Override
    public String notationExplorateur(String prefixe) {
        String res = prefixe + getLabelExplorateur() + "\n";
        String prefixeSuiv = prefixe + "   ";
        for (String nomParam : mapParametres.keySet()) {
            res += prefixeSuiv + nomParam;
        }
        return res;
    }

    @Override
    public String getLabelExplorateur() {
        return "APPEL_FONCTION" + this.nomFonction;
    }
}
